package com.ruoyi.common.utils.http

import com.ruoyi.common.constant.Constants
import org.apache.commons.lang3.StringUtils
import org.slf4j.LoggerFactory
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.io.PrintWriter
import java.net.ConnectException
import java.net.SocketTimeoutException
import java.net.URL
import java.nio.charset.StandardCharsets
import java.security.SecureRandom
import java.security.cert.X509Certificate
import javax.net.ssl.*

/**
 * 通用http发送方法
 *
 * @author ruoyi
 */
object HttpUtils {
    private val log = LoggerFactory.getLogger(HttpUtils::class.java)
    /**
     * 向指定 URL 发送GET方法的请求
     *
     * @param url 发送请求的 URL
     * @param param 请求参数，请求参数应该是 name1=value1&name2=value2 的形式。
     * @param contentType 编码类型
     * @return 所代表远程资源的响应结果
     */
    fun sendGet(url: String, param: String , contentType: String? ): String {
        val result = StringBuilder()
        var `in`: BufferedReader? = null
        try {
            val urlNameString = if (StringUtils.isNotBlank(param)) "$url?$param" else url
            log.info("sendGet - {}", urlNameString)
            val realUrl = URL(urlNameString)
            val connection = realUrl.openConnection()
            connection.setRequestProperty("accept", "*/*")
            connection.setRequestProperty("connection", "Keep-Alive")
            connection.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)")
            connection.connect()
            `in` = contentType?.let { InputStreamReader(connection.getInputStream(), it) }?.let { BufferedReader(it) }
            var line: String?
            while (`in`?.readLine().also { line = it } != null) {
                result.append(line)
            }
            log.info("recv - $result")
        } catch (e: ConnectException) {
            log.error("调用HttpUtils.sendGet ConnectException, url=$url,param=$param", e)
        } catch (e: SocketTimeoutException) {
            log.error("调用HttpUtils.sendGet SocketTimeoutException, url=$url,param=$param", e)
        } catch (e: IOException) {
            log.error("调用HttpUtils.sendGet IOException, url=$url,param=$param", e)
        } catch (e: Exception) {
            log.error("调用HttpsUtil.sendGet Exception, url=$url,param=$param", e)
        } finally {
            try {
                `in`?.close()
            } catch (ex: Exception) {
                log.error("调用in.close Exception, url=$url,param=$param", ex)
            }
        }
        return result.toString()
    }
    /**
     * 向指定 URL 发送GET方法的请求
     *
     * @param url 发送请求的 URL
     * @param param 请求参数，请求参数应该是 name1=value1&name2=value2 的形式。
     * @return 所代表远程资源的响应结果
     */
    fun sendGet(url: String, param: String ): String {
        return sendGet(url, param, Constants.UTF8)
    }
    /**
     * 向指定 URL 发送GET方法的请求
     *
     * @param url 发送请求的 URL
     * @return 所代表远程资源的响应结果
     */
    fun sendGet(url: String): String {
        return sendGet(url, StringUtils.EMPTY, Constants.UTF8)
    }

    /**
     * 向指定 URL 发送POST方法的请求
     *
     * @param url 发送请求的 URL
     * @param param 请求参数，请求参数应该是 name1=value1&name2=value2 的形式。
     * @return 所代表远程资源的响应结果
     */
    fun sendPost(url: String, param: String): String {
        var out: PrintWriter? = null
        var `in`: BufferedReader? = null
        val result = StringBuilder()
        try {
            log.info("sendPost - {}", url)
            val realUrl = URL(url)
            val conn = realUrl.openConnection()
            conn.setRequestProperty("accept", "*/*")
            conn.setRequestProperty("connection", "Keep-Alive")
            conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)")
            conn.setRequestProperty("Accept-Charset", "utf-8")
            conn.setRequestProperty("contentType", "utf-8")
            conn.doOutput = true
            conn.doInput = true
            out = PrintWriter(conn.getOutputStream())
            out.print(param)
            out.flush()
            `in` = BufferedReader(InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))
            var line: String?
            while (`in`.readLine().also { line = it } != null) {
                result.append(line)
            }
            log.info("recv - {}", result)
        } catch (e: ConnectException) {
            log.error("调用HttpUtils.sendPost ConnectException, url=$url,param=$param", e)
        } catch (e: SocketTimeoutException) {
            log.error("调用HttpUtils.sendPost SocketTimeoutException, url=$url,param=$param", e)
        } catch (e: IOException) {
            log.error("调用HttpUtils.sendPost IOException, url=$url,param=$param", e)
        } catch (e: Exception) {
            log.error("调用HttpsUtil.sendPost Exception, url=$url,param=$param", e)
        } finally {
            try {
                out?.close()
                `in`?.close()
            } catch (ex: IOException) {
                log.error("调用in.close Exception, url=$url,param=$param", ex)
            }
        }
        return result.toString()
    }

    fun sendSSLPost(url: String, param: String): String {
        val result = StringBuilder()
        val urlNameString = "$url?$param"
        try {
            log.info("sendSSLPost - {}", urlNameString)
            val sc = SSLContext.getInstance("SSL")
            sc.init(null, arrayOf<TrustManager>(TrustAnyTrustManager()), SecureRandom())
            val console = URL(urlNameString)
            val conn = console.openConnection() as HttpsURLConnection
            conn.setRequestProperty("accept", "*/*")
            conn.setRequestProperty("connection", "Keep-Alive")
            conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)")
            conn.setRequestProperty("Accept-Charset", "utf-8")
            conn.setRequestProperty("contentType", "utf-8")
            conn.doOutput = true
            conn.doInput = true
            conn.sslSocketFactory = sc.socketFactory
            conn.hostnameVerifier = TrustAnyHostnameVerifier()
            conn.connect()
            val `is` = conn.inputStream
            val br = BufferedReader(InputStreamReader(`is`))
            var ret: String?
            while (br.readLine().also { ret = it } != null) {
                if (ret != null && "" != ret!!.trim { it <= ' ' }) {
                    result.append(String(ret!!.toByteArray(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8))
                }
            }
            log.info("recv - $result")
            conn.disconnect()
            br.close()
        } catch (e: ConnectException) {
            log.error("调用HttpUtils.sendSSLPost ConnectException, url=$url,param=$param", e)
        } catch (e: SocketTimeoutException) {
            log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=$url,param=$param", e)
        } catch (e: IOException) {
            log.error("调用HttpUtils.sendSSLPost IOException, url=$url,param=$param", e)
        } catch (e: Exception) {
            log.error("调用HttpsUtil.sendSSLPost Exception, url=$url,param=$param", e)
        }
        return result.toString()
    }

    private class TrustAnyTrustManager : X509TrustManager {
        override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {}
        override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {}
        override fun getAcceptedIssuers(): Array<X509Certificate> {
            return arrayOf()
        }
    }

    private class TrustAnyHostnameVerifier : HostnameVerifier {
        override fun verify(hostname: String, session: SSLSession): Boolean {
            return true
        }
    }
}
